<html>

<head>
<title>Calculator</title>
</head>

<body bgcolor=A4A4A4>
	<h2>Calculator</h2>
	<table border=0>

		<form method="post">
			<tr>
				<td colspan=2>
				<i>by Pavan Challagulla (Student ID# 103987137)</i>
				</td>
			</tr>	
			<tr>
				<td colspan=2>
				<br>Type an expression below and click calculate.
				</td>
			</tr>
			<tr>
				<td><input type="text" name="expr"
					value="<?php echo $_REQUEST["expr"]; ?>"></input>
				</td>
				<td><input type="submit" name="submit" value="Calculate"></input>
				</td>
			</tr>
			<tr>
				<td colspan=2>
				</td>
			</tr>	
		</form>

		<?php

		$ptr;
		$tokens;
		$cleanedptr;
		$cleanedtokens;
		main();


		function error($str)
		{
			echo "<tr>
				<td colspan=2 bgcolor=FB936D><br><b>".$str."</b><br></td></tr>";
			exit(1);
		}

		function debug($str)
		{
// 			echo "<tr>
// 				<td colspan=2 bgcolor=C6F0EF><i>".$str."</i></td></tr>";
		}

		function main()
		{
			$expr = $_REQUEST["expr"];

			if($expr!=NULL)
			{
				tokenize($expr);
				parse();
				$ans = compute();
				echo "<tr>
				<td colspan=2 bgcolor=3CB051><br><b>ANSWER: </b>".$ans."<br></td></tr>";
			}
		}

		function tokenize($expr)
		{
			global $tokens;

			$j=0;
			for($i=0;$i<strlen($expr); $i++)
			{
				switch(substr($expr,$i,1))
				{
					case ' ':
						break; //ignoring spaces
					case '1':
					case '2':
					case '3':
					case '4':
					case '5':
					case '6':
					case '7':
					case '8':
					case '9':
					case '0':
					case '+':
					case '-':
					case '/':
					case '*':
					case '.':
						$tokens[$j++]=substr($expr,$i,1);
						break;
					default:
						error("Invalid expression !");
				}
			}
			$tokens[$j]='NULL';
		}

		/*
		 -------------------------------------------
		Goal = S

		S = A+A | A-A | A
		=> S = A S'
		=> S' = + or - S | (NULL)

		A = B*B | B/B | B
		=> A = B A'
		=> A' = * or / A | (NULL)

		B = -C | C

		C = [0-9] kleene star . [0-9] kleene plus
		-------------------------------------------
		Symbol		First			Follows
		-------------------------------------------
		S			-,.,[0-9]		$
		S'			+,-				$
		A			-,.,[0-9]		+,-,$
		A'			*,/				+,-,$
		B			-,.,[0-9]		+,-,*,/,$
		C			.,[0-9]			+,-,*,/,$
		-------------------------------------------
		*/


		function nextToken()
		{
			global $ptr;
			global $tokens;
			return $tokens[$ptr];
		}

		function eatToken()
		{
			global $ptr;
			global $tokens;
			global $cleanedptr;
			global $cleanedtokens;
			debug("EAT: ".$tokens[$ptr]);
			$cleanedtokens[$cleanedptr++]=$tokens[$ptr++];
		}

		function eatNumber()
		{
			global $ptr;
			global $tokens;
			global $cleanedptr;
			global $cleanedtokens;
			if(nextToken()=='-')
			{
				$cleanedtokens[$cleanedptr]=$cleanedtokens[$cleanedptr].$tokens[$ptr++];
			}
			while(isNextDigit())
			{
				$cleanedtokens[$cleanedptr]=$cleanedtokens[$cleanedptr].$tokens[$ptr++];
			}
			if(nextToken()=='.')
			{
				$cleanedtokens[$cleanedptr]=$cleanedtokens[$cleanedptr].$tokens[$ptr++];
				if(isNextDigit())
				{
					while(isNextDigit())
					{
						$cleanedtokens[$cleanedptr]=$cleanedtokens[$cleanedptr].$tokens[$ptr++];
					}
				}
				else{
					error("Incorrect syntax !");
				}
			}
			$cleanedptr++;
		}

		function isNextDigit()
		{
			if(nextToken() == '0' || nextToken() == '1'|| nextToken() == '2'|| nextToken() == '3'|| nextToken() == '4'|| nextToken() == '5'|| nextToken() == '6'|| nextToken() == '7'|| nextToken() == '8' || nextToken() == '9')
				return 1;
			else
				return 0;
		}
		function parse()
		{
			global $ptr;
			$ptr=0;
			debug("<b>Parse: </b>");
			parse_S();

			global $cleanedtokens;
				echo "<tr>
				<td colspan=2 bgcolor=F6D568><br><b>Expression: </b>";
			foreach ($cleanedtokens as $token)
			{
				echo $token." ";
			}
			echo "</td></tr>";
		}

		function parse_S()
		{
			debug("S: ".nextToken());
			if(nextToken() == '-' || nextToken() == '.' || isNextDigit())
			{
				parse_A();
				parse_S_prime();
			}
			else
			{
				error("Incorrect syntax !");
			}
		}

		function parse_S_prime()
		{
			debug("S prime: ".nextToken());
			if(nextToken()=='+' || nextToken()=='-')
			{
				eatToken();
				parse_S();
			}
			else if (nextToken()=='NULL')
			{

			}
			else
			{
				error("Incorrect syntax !");
			}
		}

		function parse_A()
		{
			debug("A: ".nextToken());

			if(nextToken() == '-' || nextToken() == '.' || isNextDigit())
			{
				parse_B();
				parse_A_prime();
			}
			else
			{
				error("Incorrect syntax !");
			}
		}

		function parse_A_prime()
		{
			debug("A prime: ".nextToken());
			if(nextToken()=='*' || nextToken()=='/')
			{
				eatToken();
				parse_A();
			}
			else if (nextToken()=='NULL' || nextToken()=='+' || nextToken()=='-')
			{

			}
			else
			{
				error("Incorrect syntax !");
			}
		}

		function parse_B()
		{
			debug("B: ".nextToken());
			if(nextToken() == '-' || nextToken() == '.' || isNextDigit())
			{
				parse_C();
			}
			else if (nextToken()=='NULL' || nextToken()=='+' || nextToken()=='-' || nextToken()=='*' || nextToken()=='/')
			{

			}
			else
			{
				error("Incorrect syntax !");
			}
		}

		function parse_C()
		{
			debug("C: ".nextToken());
			eatNumber();
		}

		function compute()
		{
			global $cleanedtokens;

			$expr = "\$ans =";
			foreach ($cleanedtokens as $token)
			{
				if($prev == '/' && floatval($token)==floatval(0))
				{
					return 'Divide by Zero Error';
				}
				else
				{
					$expr=$expr." ".$token;
					$prev = $token;
				}
			}

			eval($expr.";");

			return $ans;
		}


		?>
	</table>

</body>
</html>
